import { EntityManager, MikroORM } from '@mikro-orm/mysql';
import { InjectEntityManager, InjectMikroORM } from '@mikro-orm/nestjs';
import { Body, Controller, Get, Post, Query, Req } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { JobTasks } from "@entities/JobTasks";
import { JobTaskVO } from "@databases/vo/JobTasksVO";
import { JobProjectJobs } from "@entities/JobProjectJobs";
import { OrderJobEnrolls } from "@entities/OrderJobEnrolls";
import dayjs from 'dayjs';
import { JsonApiResponse } from '@utils/json.api.response';
import { knexPrefix, prefix } from "@databases/vo/dao-helper";
import { Users } from "@entities/Users";
import { wrap } from '@mikro-orm/core';
import { knext } from 'knext';
import { JobProjectSources } from '@entities/JobProjectSources';
import { defaultMaxListeners } from 'events';
import { UserskVO } from '@databases/vo/UserVO';
import { OrderJobEnrollsVO } from '@databases/vo/OrderJobEnrollersVO';
import * as _ from 'lodash'
import * as XLSX from 'xlsx'
import { JobTasksPictures } from '@databases/entities/JobTasksPictures';

@ApiTags('(管理员) 兼职-任务')
@Controller('task')
export class TaskController {
    constructor(
        @InjectMikroORM('zp')
        private readonly orm: MikroORM,
        @InjectEntityManager('zp')
        private readonly em: EntityManager
    ) { }

    @Post('create_simple')
    async createSimple(@Req() request,@Body() body) {
        let sql = knext(this)

        if(!body.title)
        {
            body.title = await sql.fromORM(JobProjectSources).select('title').where('id',body.source_id).getOne();
        }
        
        let result = await sql.fromORM(JobTasks).insert({
            creator_id: request.user.id,
            owner_id: request.user.id,
            source_id: body.source_id,
            start_date: body.start_date,
            created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
            updated_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
        }).getOne()

        if(result)
        {
            result = await sql.fromORM(JobTasks).where('id',result).getOne()
        }

        return JsonApiResponse.object(result)
    }

    @ApiOperation({ summary: '创建任务 (创建 C)' })
    @Post('create')
    async create(@Req() request,
        @Body() formData,
        @Body('source_id') source_id,
        //信息
        @Body('title') title,
        @Body('content') content,
        @Body('qrcode_url') qrcode_url,
        //@价值
        @Body('price') price,
        @Body('price_type') price_type,
        @Body('settle_type') settle_type,
        //数量
        @Body('staff_num') staff_num,

        //时间
        @Body('start_date') start_date,
        //位置
        @Body('location_name') location_name,
        @Body('latitude') latitude,
        @Body('longitude') longitude,
        @Body('address') address,
        //区域
        @Body('province') province,
        @Body('city') city,
        @Body('district') district,
        //业务
        @Body('is_up_sign') is_up_sign = true,
        @Body('is_down_sign') is_down_sign = true,
        @Body('is_allow_resign') allow_resign = true,
        @Body('is_allow_agent_sign') allow_agent_sign = true,
        @Body('is_notify') is_notify = true,
        //子资源
        @Body('jobs') jobs = []
    ) {

        let knex = knext(this)

        let result = await knex.fromORM(JobTasks)
            .insert({
                creator_id: request.user.id,
                owner_id: request.user.id,
                source_id,
                title,
                start_date,
                location_name,
                latitude,
                longitude,
                address,
                province,
                city,
                price_type,
                price,
                settle_type,
                staff_num,
                district,
                qrcode_url,
                content,
                is_up_sign,
                is_down_sign,
                allow_resign,
                allow_agent_sign,
                is_notify,
                created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
                updated_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
            }, ['content']).getOne()

        jobs = jobs.map(job => {
            job.task_id = result
            job.created_at = dayjs().format('YYYY-MM-DD HH:mm:ss')
            job.updated_at = dayjs().format('YYYY-MM-DD HH:mm:ss')
            return job
        })

        await knex.fromORM(JobProjectJobs)
            .insert(jobs)

        return JsonApiResponse.new(result);
    }

    // @ApiOperation({summary:'MM'})
    @Post('update')
    async update(
        @Req() request,
        @Body() formData
    ) {

        let fields = _.pick(formData, [
            'source_id',
            'start_date',
            'price_type',
            'price',
            'settle_type',
            'staff_num',
            'content',
            'qrcode_url',
            'location_name',
            'latitude',
            'longitude',
            'address',
            'province',
            'city',
            'district',
            'is_up_sign',
            'is_down_sign',
            'is_allow_resign',
            'is_allow_agent_sign',
            'is_notify',
            'is_public'
        ])

        console.log(fields)

        let knex = knext(this)
        let result = await knex.fromORM(JobTasks)
            .update({
                ...fields,
                updated_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
            }).where({ id: formData.id })
            .getOne()

        let jobs = formData.jobs

        for (const job of jobs) {
            if (job.id) {
                let jobId = job.id
                delete job.id
                delete job.created_at
                job.updated_at = dayjs().format('YYYY-MM-DD HH:mm:ss')

                await knex.fromORM(JobProjectJobs)
                    .update(job)
                    .where('id', jobId)
            } else {
                job.task_id = formData.id
                job.created_at = dayjs().format('YYYY-MM-DD HH:mm:ss')
                job.updated_at = dayjs().format('YYYY-MM-DD HH:mm:ss')

                await knex.fromORM(JobProjectJobs)
                    .insert(job)
            }
        }

        return JsonApiResponse.new(result);
    }

    @ApiOperation({ summary: '日程 (分类M)' })
    @Get('itinerary')
    async itinerary(@Req() request, @Query() query) {
        const knex = knext(this)
        const user_id = request.user.id

        const nowDate = dayjs().format('YYYY-MM-DD')
        const nowTime = dayjs().format('HH:mm:ss')

        const itinerary = await knex.fromORM(JobTasks)
            .select(
                'start_date',
                knex.raw('count(*) as count')
            )
            .where('start_date', '>=', nowDate)
            .andWhere('creator_id', user_id)
            .groupBy('start_date')
            .orderBy('start_date', 'asc')
            .populate()

        let today = await knex.fromORM(JobTasks)
            .join(
                knex.fromORM(JobProjectJobs)
                    .where('start_time', '>=', nowTime)
                    .subQueryRaw()
                ,
                function (qb) {
                    qb.on(
                        knex.tableField(JobTasks, 'id'),
                        knex.tableField(JobProjectJobs, 'task_id')
                    )
                }
            )
            .where('start_date', nowDate)
            .andWhere('creator_id', user_id)
            .groupBy('start_date')
            .orderBy('start_date', 'asc')
            .getOne()

        today = today ? today : { 'start_date': nowDate, 'job_count': 0 }

        return JsonApiResponse.new({ itinerary, today })

    }

    // @ApiOperation({summary:'当日任务列表 (列表 L)'})
    // @Get('list/date')
    // async listDate(@Req() request,@Query() query){
    //     const knex = knext(this)
    //     const orm = this.orm

    //     const start_date = query.start_date || dayjs().format('YYYY-MM-DD')
    //     const page = query.page || 1
    //     const size = query.size || 5

    //     const result = await knex
    //     .fromORM(JobTasks)
    //     .select([
    //         ...knexPrefix(JobTaskVO.baseInfo()),
    //         //
    //         knex
    //         .fromORM(JobProjectJobs)
    //         .select(knex.raw('COUNT(*)'))
    //         .where("task_id",knex.ref('job_tasks.id'))
    //         .as('jobs_count'),
    //         //
    //         knex
    //         .fromORM(OrderJobEnrolls)
    //         .select(knex.raw('COUNT(*)'))
    //         .where("job_task_id",knex.ref('job_tasks.id'))
    //         .as('enrolls_count'),
    //         //
    //         knex
    //         .fromORM(OrderJobEnrolls)
    //         .select(knex.raw('COUNT(*)'))
    //         .where("job_task_id",knex.ref('job_tasks.id'))
    //         .whereNotNull('assigned_job_at')
    //         .as('comfirm_count'),
    //         //
    //         knex
    //         .fromORM(OrderJobEnrolls)
    //         .select(knex.raw('COUNT(*)'))
    //         .where("job_task_id",knex.ref('job_tasks.id'))
    //         .whereNotNull('sign_up_at')
    //         .as('sign_up_count'),
    //         //
    //         knex
    //         .fromORM(OrderJobEnrolls)
    //         .select(knex.raw('COUNT(*)'))
    //         .where("job_task_id",knex.ref('job_tasks.id'))
    //         .whereNotNull('sign_down_at')
    //         .as('sign_down_count')
    //     ])
    //     .where('start_date', start_date)
    //     .where('creator_id', request['user'].id)
    //     .map(item=>{
    //         item.title = item.source.title
    //         return item
    //     })
    //     .withEntity(JobProjectSources,'source')
    //     .withEntity(JobProjectJobs,'jobs')
    //     .filter(item=>{
    //         return item.jobs.length > 0
    //     })
    //     .paginate(page,size)
    //     .populate()

    //     return JsonApiResponse.new({data:result})
    // }

    @ApiOperation({ summary: '所有任务列表 (列表 L)' })
    @Get('list/all')
    async listAll(
        @Req() request,
        @Query() query,
        @Query('is_public') is_public
    ) {
        const knex = knext(this)

        const start_date = query.start_date //|| dayjs().format('YYYY-MM-DD')
        const source_id = query.source_id || null
        const type = query.type || 'all'
        const page = query.page || 1
        const size = query.size || 5

        let tasks = knex
            .fromORM(JobTasks)
            .select([
                ...knexPrefix(JobTaskVO.baseInfo()),
                //
                knex
                    .fromORM(JobProjectJobs)
                    .select(knex.raw('COUNT(*)'))
                    .where("task_id", knex.ref('job_tasks.id'))
                    .as('jobs_count'),
                //
                knex
                    .fromORM(JobProjectJobs)
                    .select(knex.raw('SUM(num)'))
                    .where("task_id", knex.ref('job_tasks.id'))
                    .as('recruit_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .as('enrolls_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .whereNotNull('assigned_job_at')
                    .as('comfirm_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .whereNotNull('sign_up_at')
                    .as('sign_up_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .whereNotNull('sign_down_at')
                    .as('sign_down_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .whereNotNull('verified_at')
                    .as('verified_count'),
                //
                knex
                    .fromORM(OrderJobEnrolls)
                    .select(knex.raw('COUNT(*)'))
                    .where("job_task_id", knex.ref('job_tasks.id'))
                    .whereNotNull('give_salary_at')
                    .as('give_salary_count')
            ])
            //.where('start_date', start_date)
            //.where('creator_id', request['user'].id)
            .withEntity(Users, 'creator')
            .withEntity(JobProjectJobs, 'jobs')
            .withEntity(JobProjectSources, 'source', null, 'task')
            .withEntity(JobTasksPictures, 'pictures')

        // .filter(item=>{
        //     return item.jobs.length > 0
        // })

        if (source_id) {
            tasks = tasks.where('source_id', source_id);
        }

        if (start_date) {
            tasks = tasks.where('start_date', start_date);
        }

        // if(is_public)
        // {
        //     tasks = tasks.where('is_public', 1);
        // }


        if (type) {
            switch (type) {
                case 'all':
                    break;
                case 'doing': //1.进行中 2.未开始 3.未完结 4.已完结 5.已取消
                    tasks.where('start_date', dayjs().format('YYYY-MM-DD'));
                    tasks.whereNull('completed_at'); //未完成
                    tasks.whereNull('canceled_at'); //未取消
                    break;
                case 'not-started':
                    tasks.where('start_date', '>', dayjs().format('YYYY-MM-DD'));
                    tasks.whereNull('completed_at'); //未完成
                    tasks.whereNull('canceled_at'); //未取消
                    break;
                case 'unfinished':
                    tasks.where('start_date', '<', dayjs().format('YYYY-MM-DD'));
                    tasks.whereNull('completed_at'); //未完成
                    tasks.whereNull('canceled_at'); //未取消
                    break;
                case 'finished':
                    tasks.where('start_date', '<=', dayjs().format('YYYY-MM-DD'));
                    tasks.whereNotNull('completed_at'); //已完成
                    tasks.whereNull('canceled_at'); //未取消
                    break;
                case 'canceled':
                    tasks.whereNotNull('canceled_at');
                    break;
                default:
                    return JsonApiResponse.ERR('未知查找类型');
                    break;
            }
        }

        tasks = tasks.where('creator_id', request.user.id);

        //const sql = tasks.toQuery()

        tasks.map((task) => {
            task.jobs_count = task.jobs_count ? task.jobs_count : 1
            task.title = task.title ? task.title : task.task?.title || '未命名项目'
            return task
        })

        let result = await tasks.paginate(page, size).populate()

        return JsonApiResponse.new({ data: result })
    }

    @Get('details')
    async details(@Req() request, @Query('job_task_id') job_task_id) {

        const knex = knext(this)

        const tasks = await knex.fromORM(JobTasks)
            .select([...knexPrefix(JobTaskVO.baseInfo())])
            .withEntity(JobProjectJobs, 'jobs')
            .withEntity(JobProjectSources, 'source', null, 'task')
            .withEntity(OrderJobEnrolls, 'enrolls', (qb) => {
                qb.withEntity(Users, 'enroller', (qb) => {
                    qb.select([...knexPrefix(UserskVO.baseInfo())])
                })
                    .map((entity) => {
                        entity.state_step = OrderJobEnrollsVO.calcStepStatus(entity)
                        return entity
                    })
                //qb.select([...knexPrefix(OrderJobEnrollsKvs.baseInfo())])
            })
            .map((task) => {
                task.title = task.title ? task.title : task.task?.title
                return task
            })
            .where('creator_id', request.user.id)
            .andWhere('id', job_task_id)
            .populate();

        if (tasks.length > 0)
            return JsonApiResponse.new(tasks[0])
        else
            return JsonApiResponse.new(null)

        // $tasks = JobTask::withBaseInfo()
        // ->with([
        //     'jobs',
        //     // 'jobs.enrolls' ,
        //     // 'jobs.enrolls.enroller' => function($query){
        //     //     $query->withBaseInfo()->addSelect(['id_number']);
        //     // },
        //     'enrolls' => function($query){
        //         $query->withBaseInfo();
        //     },
        //     'enrolls.enroller' => function($query){
        //         $query->withBaseInfo()->addSelect(['id_number']);
        //     },
        // ])
        // //->createdBy($request->user()->id)
        // ->byId($job_task_id)
        // ->first();


        // $tasks->enrolls->append('state_step');
        // return JsonApiResponse::new($tasks->toArray());
    }

    @Post('operate')
    async operate(
        @Body('task_ids') task_ids,
        @Body('type') type,
        @Body('op') op,
    ) {

        //return JsonApiResponse.string('OK')

        const knex = knext(this)
        const sql = knex.fromORM(JobTasks)

        if (task_ids) {
            switch (type) {
                case 'completed':
                    if (op == 'cancel') {
                        await sql.update({ 'completed_at': null }).whereIn('id', task_ids);
                    }
                    else {
                        await sql.update({ 'completed_at': dayjs().format('YYYY-MM-DD HH:mm:ss') }).whereIn('id', task_ids);
                        return JsonApiResponse.object({ 'completed_at': dayjs().format('YYYY-MM-DD HH:mm:ss') })
                    }
                    break;
                case 'completed':
                    if (op == 'cancel') {
                        await sql.update({ 'canceled_at': null }).whereIn('id', task_ids);
                    }
                    else {
                        await sql.update({ 'canceled_at': dayjs().format('YYYY-MM-DD HH:mm:ss') }).whereIn('id', task_ids);
                    }
                    break;
                default:
                    return JsonApiResponse.ERR('该操作不存在');
            }
        }
    }

    @Get('activity')
    async activity(@Req() request) {
        let sql = knext(this)

        let tasks = await sql.fromORM(JobTasks)
            //.select('project')
            .distinct('source_id')
            .where('creator_id', 154) //request.user.id
            //.where('start_date','<=',dayjs('2024-04-20').format('YYYY-MM-DD'))
            .where('completed_at', null)

        let projects = await sql.fromORM(JobProjectSources)
            .select('*')
            .whereIn('id', tasks.map((t) => t.source_id))
            .withEntity(JobTasks, 'tasks', (qb) => {
                qb.withEntity(JobProjectJobs, 'jobs')
                qb.withEntity(OrderJobEnrolls, 'enrolls')
            })
            .populate()

        // let all = await sql.fromORM(JobTasks)
        // .whereIn('source_id',tasks.map((t)=>t.source_id))

        return JsonApiResponse.object(projects)
    }
}


